home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiniExamples / AppKit / WhatsUpDoc / DocController.m < prev    next >
Text File  |  1995-06-12  |  8KB  |  337 lines

  1. /* DocController.m
  2.  * Purpose:  This is the main controlling class for this application.
  3.  *    DocController loads the Info and Help nib files on demand.
  4.  *    DocController also handles the multiple documents that can
  5.  *    be open at any time using the Document class -- including
  6.  *    keeping a count, tracking the current active document, 
  7.  *    managing the open and save panels, etc.
  8.  *
  9.  * You may freely copy, distribute, and reuse the code in this example.
  10.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  11.  * fitness for any particular use.
  12.  *
  13.  * Written by: R. Dunbar Poor
  14.  * Created: 28/April/1991
  15.  *
  16.  */
  17.  
  18. #import "DocController.h"
  19. #import "Document.h"
  20. #import <appkit/Application.h>
  21. #import <appkit/Cell.h>
  22. #import <appkit/OpenPanel.h>
  23. #import <appkit/Panel.h>    /* for NX_ALERTxxx */
  24. #import <strings.h>
  25. #import <sys/param.h>
  26.  
  27. @interface DocController(DocControllerPrivate)
  28. - _countDocuments:aDocument :sender;
  29. - _save:aDocument :sender;
  30. - _collectEditedDocuments:aDocument :editedDocuments;
  31. - _hide:aDocument :sender;
  32. @end
  33.  
  34. @implementation DocController
  35.  
  36. - init
  37. {
  38.   [super init];
  39.   return self;
  40. }
  41.  
  42. - free
  43. {
  44.   return [super free];
  45. }
  46.  
  47. - showInfo:sender
  48. {
  49.   if (!infoPanel) {
  50.     [NXApp loadNibSection:"Info.nib" owner:self withNames:NO];
  51.   }
  52.   [infoPanel makeKeyAndOrderFront:sender];
  53.   return self;
  54. }
  55.  
  56. - showHelp:sender
  57. {
  58.   if (!helpPanel) {
  59.     [NXApp loadNibSection:"Help.nib" owner:self withNames:NO];
  60.   }
  61.   [helpPanel makeKeyAndOrderFront:sender];
  62.   return self;
  63. }
  64.  
  65. - activeDocument
  66. {
  67.   return activeDocument;
  68. }
  69.  
  70. - setActiveDocument:aDocument
  71. {
  72.   char buf[100];
  73.   
  74.   activeDocument = aDocument;
  75.  
  76.   /* display the message of the current document */
  77.   [activeDocumentField setStringValue:[activeDocument message]];
  78.  
  79.   /* count and display the number of documents present */
  80.   documentCount = 0;
  81.   [self performForDocuments:@selector(_countDocuments::) with:self];
  82.   sprintf(buf,"There %s %d active document%s.",
  83.         documentCount==1?"is":"are",
  84.       documentCount,
  85.       documentCount==1?"":"s");
  86.   [documentCountField setStringValue:buf];
  87.  
  88.   /* adjust the menu cells accordingly */
  89.   if (activeDocument) {
  90.     [saveMenu setEnabled:YES];
  91.     [saveAsMenu setEnabled:YES];
  92.     [saveToMenu setEnabled:YES];
  93.     [saveAllMenu setEnabled:YES];
  94.     if ([activeDocument isDocEdited]) {
  95.       [revertMenu setEnabled:YES];
  96.     } else {
  97.       [revertMenu setEnabled:NO];
  98.     }
  99.     [closeMenu setEnabled:YES];
  100.   } else {
  101.     [saveMenu setEnabled:NO];
  102.     [saveAsMenu setEnabled:NO];
  103.     [saveToMenu setEnabled:NO];
  104.     [saveAllMenu setEnabled:NO];
  105.     [revertMenu setEnabled:NO];
  106.     [closeMenu setEnabled:NO];
  107.   }      
  108.  
  109.   return self;
  110. }
  111.  
  112. - _countDocuments:aDocument :sender
  113. {
  114.   documentCount += 1;
  115.   return self;
  116. }
  117.  
  118. - unsetActiveDocument:aDocument
  119. {
  120.   if (activeDocument == aDocument) {
  121.     activeDocument = nil;
  122.   }
  123.   /* force an update of the document count */
  124.   [self setActiveDocument:activeDocument];
  125.   return self;
  126. }
  127.  
  128. - open:sender
  129. /*
  130.  * Open one or more existing documents
  131.  */
  132. {
  133.   const char *const *files;
  134.   static const char *const fileType[2] = {DOCUMENT_TYPE, NULL};
  135.   id openPanel;
  136.   char fullName[MAXPATHLEN];
  137.  
  138.   openPanel = [[OpenPanel new] allowMultipleFiles:YES];
  139.  
  140.   /* run the open panel, filtering for out type of document */
  141.   if ([openPanel runModalForTypes:fileType]) {
  142.     /* open all the files returned by the open panel */
  143.     files = [openPanel filenames];
  144.     for (files = [openPanel filenames]; files && *files; files++) {\
  145.       sprintf(fullName,"%s/%s",[openPanel directory],*files);
  146.       if (![[Document alloc] initFromFile:fullName]) {
  147.         NXRunAlertPanel("Open","Can't open %s", "Okay", NULL, NULL, *files);
  148.       }
  149.     }
  150.   }
  151.   return self;
  152. }
  153.  
  154. - new:sender
  155. /*
  156.  * Open a new, empty document
  157.  */
  158. {
  159.   [[Document alloc] init];
  160.   return self;
  161. }
  162.  
  163. - save:sender
  164. {
  165.   return [activeDocument save:sender];
  166. }
  167.  
  168. - saveAs:sender
  169. {
  170.   return [activeDocument saveAs:sender];
  171. }
  172.  
  173. - saveTo:sender
  174. {
  175.   return [activeDocument saveTo:sender];
  176. }
  177.  
  178. - saveAll:sender
  179. {
  180.   return [self performForDocuments:@selector(_save::) with:sender];
  181. }
  182.  
  183. - _save:aDocument :sender
  184. {
  185.   return [aDocument save:sender];
  186. }
  187.  
  188. - revert:sender
  189. {
  190.   return [activeDocument revert:sender];
  191. }
  192.  
  193. - close:sender
  194. {
  195.   return [activeDocument close:sender];
  196. }
  197.  
  198.  
  199. - performForDocuments:(SEL)aSelector with:anObject
  200. /*
  201.  * Send [self aSelector :aDocument :anObject] for each Document in the
  202.  * application.  We depend on the fact that each Document has an associated
  203.  * window and that each Document is the delegate of its window.
  204.  */
  205. {
  206.   id window, windows = [NXApp windowList];
  207.   int i=0;
  208.   
  209.   while (window = [windows objectAt:i++]) {
  210.     id document = [window delegate];
  211.     if (document && ([document class] == [Document class])) {
  212.       [self perform:aSelector with:document with:anObject];
  213.     }
  214.   }
  215.   return self;
  216. }
  217.  
  218.  
  219.  
  220. - (int)app:sender openFile:(const char *)path type:(const char *)type
  221. /*
  222.  * This method is performed whenever a user opens a document from the Workspace
  223.  * Manager. (This method has replaced the obsolete method appOpenFile:type:)
  224.  */
  225. {
  226.   if (type && !strcmp(type, DOCUMENT_TYPE)) {
  227.     if (![[Document alloc] initFromFile:path]) {
  228.       NXRunAlertPanel("Open","Can't open %s","Okay",NULL,NULL,path);
  229.       return NO;
  230.     } else {
  231.       return YES;
  232.     }
  233.   }
  234.   return NO;
  235. }
  236.  
  237. - (BOOL)appAcceptsAnotherFile:sender
  238. /*
  239.  * Inform the workspace that we can open multiple files.
  240.  */
  241. {
  242.   return YES;
  243. }
  244.  
  245. - appDidInit:sender
  246. /*
  247.  * When the app is launched, create an empty document if we haven't opened
  248.  * a document already.
  249.  */
  250. {
  251.   if (!activeDocument) {
  252.     [self new:self];
  253.   }
  254.   return self;
  255. }
  256.  
  257. - appWillTerminate:sender
  258. {
  259.   int i, editedCount, choice;
  260.   List *editedDocuments = [[List alloc] init];
  261.  
  262.   do {
  263.     /*
  264.      * Make a list of edited documents and count how many there are.
  265.      */
  266.     [editedDocuments empty];
  267.     [self performForDocuments:@selector(_collectEditedDocuments::)
  268.       with:editedDocuments];
  269.     editedCount = [editedDocuments count];
  270.  
  271.     if (editedCount > 0) {
  272.       /*
  273.        * If there is one or more unsaved document, ask the user if they want
  274.        * to review documents, quit, or abort the quit.
  275.        */
  276.       choice = NXRunAlertPanel(
  277.           "Quit",
  278.           "There are unsaved documents.\nReview them?",
  279.           "Review",        /* NX_ALERTDEFAULT */
  280.           "Quit Anyway",    /* NX_ALERTALTERNATE */
  281.           "Cancel");        /* NX_ALERTOTHER */
  282.   
  283.       switch (choice) {
  284.       case NX_ALERTDEFAULT:
  285.     /* Give the user the chance to review the edited document(s). */
  286.     for (i=0;i<editedCount;i++) {
  287.       [[editedDocuments objectAt:i] close:self];
  288.     }
  289.         break;
  290.       case NX_ALERTALTERNATE:
  291.         /* user selected Quit Anyway, just go to endgame */
  292.     editedCount = 0;
  293.         break;
  294.       case NX_ALERTOTHER:
  295.         /* user selected Cancel, return nil to cancel the quit */
  296.     [editedDocuments free];
  297.     return nil;
  298.     break;
  299.       }
  300.     }
  301.   } while (editedCount > 0);
  302.  
  303.   /*
  304.    * ENDGAME:
  305.    * hide all the windows first to avoid the irritation of watching
  306.    * each window become the main window in turn while we're closing
  307.    * documents.  After all, we simply want to quit...
  308.    */
  309.   [self performForDocuments:@selector(_hide::) with:self];
  310.   [editedDocuments free];
  311.   /* ...and terminate without any futher ado (or review of docs) */
  312.   return self;
  313. }
  314.  
  315. - _collectEditedDocuments:aDocument :editedDocuments
  316. /*
  317.  * Collect those documents that have been modified into the editedDocuments
  318.  * list.  Called from performForDocuments:with:.
  319.  */ 
  320. {
  321.   if ([aDocument isDocEdited]) {
  322.     [editedDocuments addObject:aDocument];
  323.   }
  324.   return self;
  325. }
  326.  
  327. - _hide:aDocument :sender
  328. /*
  329.  * hide one document.
  330.  */
  331. {
  332.   return [aDocument hideDocument:sender];
  333. }
  334.  
  335.  
  336. @end
  337.